/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.zumbits.avd.storage;

import br.com.zumbits.avd.Config;
import br.com.zumbits.avd.Constants;
import br.com.zumbits.avd.logger.Log;
import br.com.zumbits.avd.comunication.Protocol;
import br.com.zumbits.avd.server.Base64;
import br.com.zumbits.avd.subversion.SvnManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.List;
import java.util.Random;

/**
 *
 * @author zumbits
 */
public class StorageManager {

    public static final String FILE;
    public static final String PATH;

    static {
        List<String> list = Config.getPathStorage();
        FILE = list.get(0);
        PATH = list.get(1);
    }
    //
    private SvnManager svnManager;

    public StorageManager() {
        svnManager = new SvnManager();
    }

    /**
     *
     * @param user
     * @param path
     * @param name
     * @return
     */
    private boolean isFile(String user, String path, String name) {
        return new File(getRealPath(File.separator + user + File.separator + path + File.separator + name)).isFile();
    }

    private boolean isDirectory(String path) {
        return new File(getRealPath(path)).isDirectory();
    }

    private String getRealPath(String path) {
        return PATH + File.separator + path;
    }

    public long getFreeSpace(String path) {
        return new File(getRealPath(path)).getFreeSpace();
    }

    public long getTotalSpace(String path) {
        return new File(getRealPath(path)).getTotalSpace();
    }

    public long getUsableSpace(String path) {
        return new File(getRealPath(path)).getUsableSpace();
    }

    /**
     * 
     * @param user
     * @param path
     * @param name
     * @return
     */
    public int getVersion(String user, String path, String name) {
        path = getRealPath(File.separator + user + File.separator + path);

        svnManager.start(path);
        return svnManager.getVersion(name);
    }

    /**
     * 
     * @param user
     * @param path
     * @param name
     * @return
     */
    public boolean exists(String user, String path, String name) {
        path = File.separator + user + File.separator + path + File.separator + name;
        return new File(getRealPath(path)).exists();
    }

    /**
     * 
     * @param user
     * @param path
     * @return
     */
    public String listFiles(String user, String path) {
        String list = "";

        String realPath = getRealPath(File.separator + user + File.separator + path);

        File currDir = new File(realPath);
        File listFiles[] = currDir.listFiles();

        for (int i = 0; i < listFiles.length; i++) {
            if (listFiles[i].isDirectory()) {
                list +=
                        Constants.TAB + "<folder>" + Constants.NEWLINE
                        + Constants.TAB + Constants.TAB + "<name>" + listFiles[i].getName() + "</name>" + Constants.NEWLINE
                        + Constants.TAB + "</folder>" + Constants.NEWLINE;
            }
        }

        for (int i = 0; i < listFiles.length; i++) {
            if (listFiles[i].isFile() && !listFiles[i].getName().equals(FILE)) {
                list +=
                        Constants.TAB + "<file>" + Constants.NEWLINE
                        + Constants.TAB + Constants.TAB + "<name>" + listFiles[i].getName() + "</name>" + Constants.NEWLINE
                        + Constants.TAB + Constants.TAB + "<size>" + listFiles[i].length() + "</size>" + Constants.NEWLINE
                        + Constants.TAB + Constants.TAB + "<version>" + getVersion(user, path, listFiles[i].getName()) + "</version>" + Constants.NEWLINE
                        + Constants.TAB + "</file>" + Constants.NEWLINE;
            }
        }

        return list;
    }

    /**
     *
     * @param user
     * @param path
     * @param name
     * @return
     */
    public boolean createFolder(String user, String path, String name) {
        String realPath = getRealPath(File.separator + user + File.separator + path + File.separator + name);
        boolean ok = new File(realPath).mkdir();

        svnManager.start(realPath);

        Log.print(user, "Create Folder: " + path + File.separator + name);

        return ok;
    }

    /**
     * 
     * @param user
     * @param path
     * @param name
     * @return
     */
    public boolean delete(String user, String path, String name) {
        String realPath = getRealPath(user + path);

        if (isFile(user, path, name)) {
            svnManager.start(realPath);
            svnManager.delete(name);
        }

        realPath += File.separator + name;

        Log.print(user, "Remove: " + new String(path + File.separator + name).replace("//", "/"));

        realPath = realPath.replace("//", "/");

        try {
            Runtime.getRuntime().exec("rm -rf " + realPath);
            return true;
        } catch (Exception ex) {
            //Nothing here
        }

        return false;

    }

    /**
     * 
     * @param user
     * @param path
     * @param name
     * @param newPath
     * @param newName
     * @return
     */
    public boolean move(String user, String path, String name, String newPath, String newName) {
        String realPath = getRealPath(File.separator + user + File.separator + path);
        String realNewPath = getRealPath(File.separator + user + File.separator + newPath);

        boolean moveDisk = new File(realPath + File.separator + name).renameTo(
                new File(realNewPath + File.separator + newName));

        if (moveDisk) {
            int version = getVersion(user, path, name);

            svnManager.start(realPath);
            svnManager.delete(name);

            svnManager.start(realNewPath);
            svnManager.add(newName, version);

            Log.print(user, "Move from: " + path + File.separator + name
                    + " to " + (path + File.separator + newName));
        }

        return moveDisk;
    }

    /**
     *
     * @param path
     * @param copyPath
     * @return
     * @throws IOException
     */
    public boolean copy(String user, String path, String name, String copyPath, String copyName) throws IOException {
        String realPath = getRealPath(File.separator + user + File.separator + path + File.separator + name);
        String realCopyPath = getRealPath(File.separator + user + File.separator + copyPath);

        File inputFile = new File(realPath);
        File outputFile = new File(realCopyPath + File.separator + copyName);

        if (realPath.equals(realCopyPath + File.separator + copyName)) {
            return false;
        }

        if (inputFile.isDirectory()) {
            //Para linux somente
            Runtime.getRuntime().exec("cp -R " + realPath + " " + (realCopyPath + File.separator + copyName));
            Log.print(user, "Copy Folder: " + realPath + " to " + (realCopyPath + File.separator + copyName));
        } else if (inputFile.isFile()) {
            int version = getVersion(user, path, name);

            FileReader in = new FileReader(inputFile);
            FileWriter out = new FileWriter(outputFile);
            int c;

            while ((c = in.read()) != -1) {
                out.write(c);
            }

            in.close();
            out.close();

            svnManager.start(realCopyPath + File.separator + copyName);
            svnManager.add(name, version);

            Log.print(user, "Copy File: " + path + File.separator + name
                    + " to " + (copyPath + File.separator + copyName));

            return true;

        }

        return false;
    }

    /**
     * 
     * @param user
     * @param path
     * @param name
     * @return
     */
    public String fileURL_SAFE_B64(String user, String path, String name, int part, int totalParts) {
        FileInputStream fileInputStream = null;

        try {
            path = File.separator + user + path + File.separator + name;

            File file = new File(getRealPath(path));
            fileInputStream = new FileInputStream(file);

            int lenghtTotal = (int) file.length();
            int lenght = (int) Math.ceil((double)lenghtTotal / (double)totalParts);
            int ini = (part - 1) * lenght;

            if (part == totalParts) {
                lenght = lenghtTotal - ((part - 1) * lenght);
            }

            byte[] b = new byte[lenght];

            fileInputStream.skip(ini);
            fileInputStream.read(b);

            return Base64.encodeBytes(b, Base64.URL_SAFE);
        } catch (Exception ex) {
            Log.print("error", "Error Base_64 " + ex.getMessage());
        } finally {
            try {
                fileInputStream.close();
            } catch (IOException ex) {
                //Nothing here
            }
        }

        return null;
    }

    /**
     * 
     * @param user
     * @param path
     * @param name
     * @param data
     * @param version
     * @return
     */
    public int upload(String user, String path, String name, int part, int totalParts, String data, int version) {
        //TODO: implementar a quebra por partes
        try {
            String realPath = getRealPath(File.separator + user + File.separator + path);

            svnManager.start(realPath);
            int versionSever = svnManager.getVersion(name);

            if (version > versionSever) {
                byte[] bytes = Base64.decode(data, Base64.URL_SAFE);
                File file = new File(realPath + File.separator + name);

                FileOutputStream fileOutputStream = new FileOutputStream(file);

                fileOutputStream.write(bytes);
                fileOutputStream.close();

                if (versionSever == -1) {
                    svnManager.add(name, version);
                } else {
                    svnManager.setVersion(name, version);
                }

                Log.print(user, "Upload: " + path + File.separator + name + " version " + version);

                return Protocol.UPLOAD_SUCESS;
            } else {
                return Protocol.UPLOAD_WRONG_VERSION;
            }
        } catch (Exception ex) {
            //TODO: gerar log de error
        }

        return Protocol.UPLOAD_UNKNOWN;
    }
}

